A walkthrough of Ernest (2005)’s original analytical approach, from close reading of the paper.
Questions
- Is energy use across body size categories (regardless of species) uniform or multimodal?
- uniform would correspond generally to energetic equivalence/Damuth’s rule.
- multimodal might suggest different resource availability for different body sizes.
- If energy use is not uniform across body size categories, does the species level body size distribution correspond to modes of energy use?
- i.e. are there more species with mean body sizes around the modes of the body size-energy use distribution?
- if so, maybe it’s good to be certain sizes, and species accumulate at those optima.
Data
Ernest data
Ernest drew data from the Andrews LTER, the Sevilleta, Niwot Ridge, and Portal. For details of these field sites, see the relevant publications cited in Ernest (2005).
Translation to replicate-becs
The same datasets are available online, from these sources.
download_raw_paper_data(storagepath = storagepath)
Process raw data into the appropriate format. This is a data table with a record for each individual and columns for species and weight in grams. By default these tables will be stored in subdirectores of replicate-becs/data/paper/processed.
process_raw_data(storagepath = storagepath)
Loading in data version 1.106.0
[1] TRUE
Load data tables for each community.
communities <- load_paper_data(storagepath = storagepath)
Each community should be a data table with columns for species and size for each individual, for example:
names(communities)[[1]]
[1] "andrews"
head(communities[[1]])
Comparing data from 2005 to data available in 2019
Although the same datasets are now available online, they may have changed somewhat since 2005 (due to error checking, etc). Ernest (2005) may also have taken some cleaning and filtering steps, the details of which could have been omitted from the manuscript due to length restrictions. For example, many studies using data from the Portal Project omit ground squirrels, because although they may be within the “small mammal” size range, they are not target taxa for the sampling method.
Ernest (2005) reported summary statistics of her datasets; here I compare them to the corresponding dataset in the 2019 data.
summary_stats_comparison = compare_summary_stats(storagepath = storagepath)
Column `community_name` joining character vector and factor, coercing into character vector
print(summary_stats_comparison)
Constructing distributions/metrics
Body size-energy use distributions (BSED)
Ernest method
- Per individual, calculate metabolic rate as metabolic rate \(B \propto M^\frac{3}{4}\) where \(M\) is mass in grams.
- Sum energy use of all individuals in body size classes of .2 natural log units.
- Also try classes of .1 and .3 natural log units
- Convert raw energy use values for each body size class into the proportion of all the energy used in that community used by that body size class. This allows for comparisons between communities.
Translation to replicate-becs
For every individual, calculate metabolic rate and assign to a size class.
communities_energy <- lapply(communities, FUN = make_community_table, ln_units = 0.2)
head(communities_energy[[1]])
For each community, sum total energy use for each size class, and convert to the proportion of total energy use for that community.
bseds <- lapply(communities_energy, FUN = make_bsed)
head(bseds[[1]])

Species-level body size distributions (BSD)
Ernest method
- Frequency distributions of mean mass of each species in a community.
- For plotting (but not statistics), smoothed using kernel density estimation.
- Gaussian kernel to mimic the actual body size distribution in log space
- avg. std dev of the mean of the logged masses = smoothing parameter \(h\)
- align sampling points with the midpoint of each size class in the BSED
- after Manly 1996, “Are there clumps in body-size distributions?”, Ecology
Translation to replicate-becs
Calculate mean mass of each species in each community.
bsds <- lapply(communities, FUN = make_bsd)
head(bsds[[1]])

Energetic dominance (\(D_E\))
- Define “energy use modes” as contiguous body size classes where the energy use of each size class > 5% of the community total.
- i.e. a little bit more than the expectation if energy use is uniform across all body sizes
- Calculate the total energy use for each species in the mode.
- Calculate the “dominance” of the species with the highest energy use in that mode as \(D_E = p_{max}\), where \(p_{max}\) is the maximum proportion of energy use by any one species in a mode.
- “a modification of the Berger-Parker dominance index (Berger and Parker 1970)”
Translation to replicate-becs
- Find contiguous size classes where each class has >5% of total energy use
- Calculate the total energy use for each species, and the proportion held by the species with the highest energy use (\(p_{max}\))
- Return \(p_{max}\) for every mode, along with the min and max size classes in that mode for each community
energetic_dom <- lapply(communities_energy, FUN = energetic_dominance)
head(energetic_dom[[1]])
- To plot, combine all modes from all communities and plot a histogram of \(D_E\) values.

Statistical tests
Compare BSEDs among communities
Ernest approach
- For every pair of communities, create a pool of masses of all individuals from both communities.
- Draw two new communities with the same number of individuals as the empirical communities, pulling masses at random from the pool, with replacement.
- Calculate the DOI for the BSEDs of the two sample communities.
- Repeat 10000 for each pair.
- The P value is the proportion of sample DOIs greater (i.e. less overlap) than the empirical value.
Translation to replicate-becs
- For every pair of communities, pool all the masses
- Resample two communities of the right sizes
- Construct BSEDs for both communities
- Calculate the DOI of the two BSEDs
- Repeat 10000x
community_combination_indices = utils::combn(x = c(1:9), m = 2, simplify = TRUE) %>%
t() %>%
as.data.frame() %>%
dplyr::rename(community_a = V1, community_b = V2)
combine_communities = function(indices, communities) {
community_combination = list(community_a = communities[[indices[1]]], community_b = communities[[indices[2]]], community_names = c(names(communities)[[indices[1]]], names(communities)[[indices[2]]]))
return(community_combination)
}
community_combinations = apply(community_combination_indices, MARGIN = 1, FUN = combine_communities, communities = communities)
bsed_crosscomm_bootstraps = lapply(community_combinations, FUN = community_bootstrap,
bootstrap_function = 'bootstrap_crosscomm_bseds', nbootstraps = 10000)


See histogram of p values for comparisons to see if commuities’ BSEDs are the same or different.
Comparing BSDs among communities
Ernest approach
Ernest (2005) used a two-sample Kolmogorov-Smirnov test to compare every possible combination of community-level BSDs.
Translation to replicate-becs
# use same community combinations as before
bsd_crosscomm_ks = lapply(community_combinations, FUN = ks_bsd,
ln_mass_vals = F)

LS0tCnRpdGxlOiAiTmFycmF0aXZlIG9mIG9yaWdpbmFsIGFuYWx5c2lzIgphdXRob3I6ICJSZW5hdGEgRGlheiIKZGF0ZTogIjUvMTQvMjAxOSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGfQpsaWJyYXJ5KHJlcGxpY2F0ZWJlY3MpCmRvd25sb2FkX2RhdGEgPSBUUlVFCnNvdXJjZV9zaW1zID0gRkFMU0UKc2V0LnNlZWQoMzUyKSAjIEdOViBhcmVhIGNvZGUsIGZvciBmdW4Kc3RvcmFnZXBhdGggPSAnL1VzZXJzL3JlbmF0YWRpYXovRGVza3RvcC90b3ktYmVjcycKI3N0b3JhZ2VwYXRoID0gaGVyZTo6aGVyZSgnZmlsZXMnKQpzZXR1cF9maWxlcyhzdG9yYWdlcGF0aCA9IHN0b3JhZ2VwYXRoKQpgYGAKCkEgd2Fsa3Rocm91Z2ggb2YgRXJuZXN0ICgyMDA1KSdzIG9yaWdpbmFsIGFuYWx5dGljYWwgYXBwcm9hY2gsIGZyb20gY2xvc2UgcmVhZGluZyBvZiB0aGUgcGFwZXIuIAoKIyMgUXVlc3Rpb25zCgoxLiBJcyBlbmVyZ3kgdXNlIGFjcm9zcyBib2R5IHNpemUgY2F0ZWdvcmllcyAocmVnYXJkbGVzcyBvZiBzcGVjaWVzKSB1bmlmb3JtIG9yIG11bHRpbW9kYWw/Ci0gdW5pZm9ybSB3b3VsZCBjb3JyZXNwb25kIGdlbmVyYWxseSB0byBlbmVyZ2V0aWMgZXF1aXZhbGVuY2UvRGFtdXRoJ3MgcnVsZS4KLSBtdWx0aW1vZGFsIG1pZ2h0IHN1Z2dlc3QgZGlmZmVyZW50IHJlc291cmNlIGF2YWlsYWJpbGl0eSBmb3IgZGlmZmVyZW50IGJvZHkgc2l6ZXMuCjIuIElmIGVuZXJneSB1c2UgaXMgbm90IHVuaWZvcm0gYWNyb3NzIGJvZHkgc2l6ZSBjYXRlZ29yaWVzLCBkb2VzIHRoZSBzcGVjaWVzIGxldmVsIGJvZHkgc2l6ZSBkaXN0cmlidXRpb24gY29ycmVzcG9uZCB0byBtb2RlcyBvZiBlbmVyZ3kgdXNlPwotIGkuZS4gYXJlIHRoZXJlIG1vcmUgc3BlY2llcyB3aXRoIG1lYW4gYm9keSBzaXplcyBhcm91bmQgdGhlIG1vZGVzIG9mIHRoZSBib2R5IHNpemUtZW5lcmd5IHVzZSBkaXN0cmlidXRpb24/Ci0gaWYgc28sIG1heWJlIGl0J3MgZ29vZCB0byBiZSBjZXJ0YWluIHNpemVzLCBhbmQgc3BlY2llcyBhY2N1bXVsYXRlIGF0IHRob3NlIG9wdGltYS4KCgojIyBEYXRhCgojIyMjIEVybmVzdCBkYXRhCkVybmVzdCBkcmV3IGRhdGEgZnJvbSB0aGUgQW5kcmV3cyBMVEVSLCB0aGUgU2V2aWxsZXRhLCBOaXdvdCBSaWRnZSwgYW5kIFBvcnRhbC4gRm9yIGRldGFpbHMgb2YgdGhlc2UgZmllbGQgc2l0ZXMsIHNlZSB0aGUgX3JlbGV2YW50IHB1YmxpY2F0aW9ucyBjaXRlZCBpbiBFcm5lc3QgKDIwMDUpLl8gCgojIyMjIFRyYW5zbGF0aW9uIHRvIGByZXBsaWNhdGUtYmVjc2AKClRoZSBzYW1lIGRhdGFzZXRzIGFyZSBhdmFpbGFibGUgb25saW5lLCBfZnJvbSB0aGVzZSBzb3VyY2VzXy4gCmBgYHtyIGRvd25sb2FkIGRhdGEgaWYgbm90IGRvd25sb2FkZWQsIGluY2x1ZGUgPSBGfQppZihkb3dubG9hZF9kYXRhKSBkb3dubG9hZF9yYXdfcGFwZXJfZGF0YShzdG9yYWdlcGF0aCA9IHN0b3JhZ2VwYXRoKQpgYGAKCmBgYHtyIGRvd25sb2FkIHJhdyBkYXRhLCBldmFsID0gRn0KZG93bmxvYWRfcmF3X3BhcGVyX2RhdGEoc3RvcmFnZXBhdGggPSBzdG9yYWdlcGF0aCkKYGBgCgpQcm9jZXNzIHJhdyBkYXRhIGludG8gdGhlIGFwcHJvcHJpYXRlIGZvcm1hdC4gVGhpcyBpcyBhIGRhdGEgdGFibGUgd2l0aCBhIHJlY29yZCBmb3IgZWFjaCBpbmRpdmlkdWFsIGFuZCBjb2x1bW5zIGZvciBgc3BlY2llc2AgYW5kIGB3ZWlnaHRgIGluIGdyYW1zLiBCeSBkZWZhdWx0IHRoZXNlIHRhYmxlcyB3aWxsIGJlIHN0b3JlZCBpbiBzdWJkaXJlY3RvcmVzIG9mIGByZXBsaWNhdGUtYmVjcy9kYXRhL3BhcGVyL3Byb2Nlc3NlZGAuIAoKYGBge3IgcHJvY2VzcyBwYXBlciBkYXRhfQpwcm9jZXNzX3Jhd19kYXRhKHN0b3JhZ2VwYXRoID0gc3RvcmFnZXBhdGgpCmBgYAoKTG9hZCBkYXRhIHRhYmxlcyBmb3IgZWFjaCBjb21tdW5pdHkuIAoKYGBge3IgbG9hZCBjb21tdW5pdHkgZGF0YSwgZWNobz1UUlVFfQpjb21tdW5pdGllcyA8LSBsb2FkX3BhcGVyX2RhdGEoc3RvcmFnZXBhdGggPSBzdG9yYWdlcGF0aCkKYGBgCgpFYWNoIGNvbW11bml0eSBzaG91bGQgYmUgYSBkYXRhIHRhYmxlIHdpdGggY29sdW1ucyBmb3Igc3BlY2llcyBhbmQgc2l6ZSBmb3IgZWFjaCBpbmRpdmlkdWFsLCBmb3IgZXhhbXBsZToKCmBgYHtyIGluc3BlY3QgY29tbXVuaXR5IGRhdGF9Cm5hbWVzKGNvbW11bml0aWVzKVtbMV1dCmhlYWQoY29tbXVuaXRpZXNbWzFdXSkKYGBgCgoKIyMjIyBDb21wYXJpbmcgZGF0YSBmcm9tIDIwMDUgdG8gZGF0YSBhdmFpbGFibGUgaW4gMjAxOQoKQWx0aG91Z2ggdGhlIHNhbWUgZGF0YXNldHMgYXJlIG5vdyBhdmFpbGFibGUgb25saW5lLCB0aGV5IG1heSBoYXZlIGNoYW5nZWQgc29tZXdoYXQgc2luY2UgMjAwNSAoZHVlIHRvIGVycm9yIGNoZWNraW5nLCBldGMpLiBFcm5lc3QgKDIwMDUpIG1heSBhbHNvIGhhdmUgdGFrZW4gc29tZSBjbGVhbmluZyBhbmQgZmlsdGVyaW5nIHN0ZXBzLCB0aGUgZGV0YWlscyBvZiB3aGljaCBjb3VsZCBoYXZlIGJlZW4gb21pdHRlZCBmcm9tIHRoZSBtYW51c2NyaXB0IGR1ZSB0byBsZW5ndGggcmVzdHJpY3Rpb25zLiBGb3IgZXhhbXBsZSwgbWFueSBzdHVkaWVzIHVzaW5nIGRhdGEgZnJvbSB0aGUgUG9ydGFsIFByb2plY3Qgb21pdCBncm91bmQgc3F1aXJyZWxzLCBiZWNhdXNlIGFsdGhvdWdoIHRoZXkgbWF5IGJlIHdpdGhpbiB0aGUgInNtYWxsIG1hbW1hbCIgc2l6ZSByYW5nZSwgdGhleSBhcmUgbm90IHRhcmdldCB0YXhhIGZvciB0aGUgc2FtcGxpbmcgbWV0aG9kLiAKCkVybmVzdCAoMjAwNSkgcmVwb3J0ZWQgc3VtbWFyeSBzdGF0aXN0aWNzIG9mIGhlciBkYXRhc2V0czsgaGVyZSBJIGNvbXBhcmUgdGhlbSB0byB0aGUgY29ycmVzcG9uZGluZyBkYXRhc2V0IGluIHRoZSAyMDE5IGRhdGEuIAoKYGBge3IgY29tcGFyZSBzdW1tYXJ5IHN0YXRzfQpzdW1tYXJ5X3N0YXRzX2NvbXBhcmlzb24gPSBjb21wYXJlX3N1bW1hcnlfc3RhdHMoc3RvcmFnZXBhdGggPSBzdG9yYWdlcGF0aCkKCnByaW50KHN1bW1hcnlfc3RhdHNfY29tcGFyaXNvbikKYGBgCgoKIyMgQ29uc3RydWN0aW5nIGRpc3RyaWJ1dGlvbnMvbWV0cmljcwoKIyMjIEJvZHkgc2l6ZS1lbmVyZ3kgdXNlIGRpc3RyaWJ1dGlvbnMgKEJTRUQpCgojIyMjIEVybmVzdCBtZXRob2QKCi0gUGVyIGluZGl2aWR1YWwsIGNhbGN1bGF0ZSBtZXRhYm9saWMgcmF0ZSBhcyBtZXRhYm9saWMgcmF0ZSAkQiBccHJvcHRvIE1eXGZyYWN7M317NH0kIHdoZXJlICRNJCBpcyBtYXNzIGluIGdyYW1zLgotIFN1bSBlbmVyZ3kgdXNlIG9mIGFsbCBpbmRpdmlkdWFscyBpbiBib2R5IHNpemUgY2xhc3NlcyBvZiAuMiBuYXR1cmFsIGxvZyB1bml0cy4KLSBBbHNvIHRyeSBjbGFzc2VzIG9mIC4xIGFuZCAuMyBuYXR1cmFsIGxvZyB1bml0cwotIENvbnZlcnQgcmF3IGVuZXJneSB1c2UgdmFsdWVzIGZvciBlYWNoIGJvZHkgc2l6ZSBjbGFzcyBpbnRvIHRoZSBwcm9wb3J0aW9uIG9mIGFsbCB0aGUgZW5lcmd5IHVzZWQgaW4gdGhhdCBjb21tdW5pdHkgdXNlZCBieSB0aGF0IGJvZHkgc2l6ZSBjbGFzcy4gVGhpcyBhbGxvd3MgZm9yIGNvbXBhcmlzb25zIGJldHdlZW4gY29tbXVuaXRpZXMuCgoKIVtFcm5lc3QgMjAwNSBGaWcgMV0oLi4vYW5hbHlzaXMvZXJuZXN0MjAwNV9maWcxLnBuZykKCgojIyMjIFRyYW5zbGF0aW9uIHRvIGByZXBsaWNhdGUtYmVjc2AKCkZvciBldmVyeSBpbmRpdmlkdWFsLCBjYWxjdWxhdGUgbWV0YWJvbGljIHJhdGUgYW5kIGFzc2lnbiB0byBhIHNpemUgY2xhc3MuIAoKYGBge3IgY29uc3RydWN0IEJTRURzfQpjb21tdW5pdGllc19lbmVyZ3kgPC0gbGFwcGx5KGNvbW11bml0aWVzLCBGVU4gPSBtYWtlX2NvbW11bml0eV90YWJsZSwgbG5fdW5pdHMgPSAwLjIpCgpoZWFkKGNvbW11bml0aWVzX2VuZXJneVtbMV1dKQpgYGAKCkZvciBlYWNoIGNvbW11bml0eSwgc3VtIHRvdGFsIGVuZXJneSB1c2UgZm9yIGVhY2ggc2l6ZSBjbGFzcywgYW5kIGNvbnZlcnQgdG8gdGhlIHByb3BvcnRpb24gb2YgdG90YWwgZW5lcmd5IHVzZSBmb3IgdGhhdCBjb21tdW5pdHkuCgpgYGB7ciBtYWtlIGJzZWRzfQpic2VkcyA8LSBsYXBwbHkoY29tbXVuaXRpZXNfZW5lcmd5LCBGVU4gPSBtYWtlX2JzZWQpCgpoZWFkKGJzZWRzW1sxXV0pCmBgYAoKYGBge3IgcGxvdCBic2VkcywgZWNobz1GQUxTRSwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQoKYnNlZHNfcGxvdCA8LSBwbG90X3BhcGVyX2Rpc3RzKGJzZWRzLCBkaXN0X3R5cGUgPSAnYnNlZCcpCgppbnZpc2libGUoYnNlZHNfcGxvdCkKYGBgCgojIyMgU3BlY2llcy1sZXZlbCBib2R5IHNpemUgZGlzdHJpYnV0aW9ucyAoQlNEKQoKIyMjIyBFcm5lc3QgbWV0aG9kCi0gRnJlcXVlbmN5IGRpc3RyaWJ1dGlvbnMgb2YgbWVhbiBtYXNzIG9mIGVhY2ggc3BlY2llcyBpbiBhIGNvbW11bml0eS4KLSBGb3IgcGxvdHRpbmcgKGJ1dCBub3Qgc3RhdGlzdGljcyksIHNtb290aGVkIHVzaW5nIGtlcm5lbCBkZW5zaXR5IGVzdGltYXRpb24uIAotIEdhdXNzaWFuIGtlcm5lbCB0byBtaW1pYyB0aGUgYWN0dWFsIGJvZHkgc2l6ZSBkaXN0cmlidXRpb24gaW4gbG9nIHNwYWNlCi0gYXZnLiBzdGQgZGV2IG9mIHRoZSBtZWFuIG9mIHRoZSBsb2dnZWQgbWFzc2VzID0gc21vb3RoaW5nIHBhcmFtZXRlciAkaCQKLSBhbGlnbiBzYW1wbGluZyBwb2ludHMgd2l0aCB0aGUgbWlkcG9pbnQgb2YgZWFjaCBzaXplIGNsYXNzIGluIHRoZSBCU0VECi0gYWZ0ZXIgTWFubHkgMTk5NiwgIkFyZSB0aGVyZSBjbHVtcHMgaW4gYm9keS1zaXplIGRpc3RyaWJ1dGlvbnM/IiwgX0Vjb2xvZ3lfCgojIyMjIFRyYW5zbGF0aW9uIHRvIGByZXBsaWNhdGUtYmVjc2AKCkNhbGN1bGF0ZSBtZWFuIG1hc3Mgb2YgZWFjaCBzcGVjaWVzIGluIGVhY2ggY29tbXVuaXR5LiAKCmBgYHtyIGNvbnN0cnVjdCBic2RzfSAKCmJzZHMgPC0gbGFwcGx5KGNvbW11bml0aWVzLCBGVU4gPSBtYWtlX2JzZCkgCgpoZWFkKGJzZHNbWzFdXSkKYGBgCgpgYGB7ciBwbG90IGJzZHMsIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0KCmJzZHNfcGxvdCA8LSBwbG90X3BhcGVyX2Rpc3RzKGJzZHMsIGRpc3RfdHlwZSA9ICdic2QnKQoKaW52aXNpYmxlKGJzZHNfcGxvdCkKYGBgCgoKIyMjIEVuZXJnZXRpYyBkb21pbmFuY2UgKCREX0UkKQoKLSBEZWZpbmUgImVuZXJneSB1c2UgbW9kZXMiIGFzIGNvbnRpZ3VvdXMgYm9keSBzaXplIGNsYXNzZXMgd2hlcmUgdGhlIGVuZXJneSB1c2Ugb2YgZWFjaCBzaXplIGNsYXNzID4gNSUgb2YgdGhlIGNvbW11bml0eSB0b3RhbC4gCi0gaS5lLiBhIGxpdHRsZSBiaXQgbW9yZSB0aGFuIHRoZSBleHBlY3RhdGlvbiBpZiBlbmVyZ3kgdXNlIGlzIHVuaWZvcm0gYWNyb3NzIGFsbCBib2R5IHNpemVzCi0gQ2FsY3VsYXRlIHRoZSB0b3RhbCBlbmVyZ3kgdXNlIGZvciBlYWNoIHNwZWNpZXMgaW4gdGhlIG1vZGUuIAotIENhbGN1bGF0ZSB0aGUgImRvbWluYW5jZSIgb2YgdGhlIHNwZWNpZXMgd2l0aCB0aGUgaGlnaGVzdCBlbmVyZ3kgdXNlIGluIHRoYXQgbW9kZSBhcyAkRF9FID0gcF97bWF4fSQsIHdoZXJlICRwX3ttYXh9JCBpcyB0aGUgbWF4aW11bSBwcm9wb3J0aW9uIG9mIGVuZXJneSB1c2UgYnkgYW55IG9uZSBzcGVjaWVzIGluIGEgbW9kZS4gCi0gImEgbW9kaWZpY2F0aW9uIG9mIHRoZSBCZXJnZXItUGFya2VyIGRvbWluYW5jZSBpbmRleCAoQmVyZ2VyIGFuZCBQYXJrZXIgMTk3MCkiCgojIyMjIFRyYW5zbGF0aW9uIHRvIGByZXBsaWNhdGUtYmVjc2AKCi0gRmluZCBjb250aWd1b3VzIHNpemUgY2xhc3NlcyB3aGVyZSBlYWNoIGNsYXNzIGhhcyA+NSUgb2YgdG90YWwgZW5lcmd5IHVzZQotIENhbGN1bGF0ZSB0aGUgdG90YWwgZW5lcmd5IHVzZSBmb3IgZWFjaCBzcGVjaWVzLCBhbmQgdGhlIHByb3BvcnRpb24gaGVsZCBieSB0aGUgc3BlY2llcyB3aXRoIHRoZSBoaWdoZXN0IGVuZXJneSB1c2UgKCRwX3ttYXh9JCkKLSBSZXR1cm4gJHBfe21heH0kIGZvciBldmVyeSBtb2RlLCBhbG9uZyB3aXRoIHRoZSBtaW4gYW5kIG1heCBzaXplIGNsYXNzZXMgaW4gdGhhdCBtb2RlIGZvciBlYWNoIGNvbW11bml0eQoKYGBge3IgZW5lcmdldGljIGRvbWluYW5jZX0KCmVuZXJnZXRpY19kb20gPC0gbGFwcGx5KGNvbW11bml0aWVzX2VuZXJneSwgRlVOID0gZW5lcmdldGljX2RvbWluYW5jZSkgCgpoZWFkKGVuZXJnZXRpY19kb21bWzFdXSkKCmBgYAoKLSBUbyBwbG90LCBjb21iaW5lIGFsbCBtb2RlcyBmcm9tIGFsbCBjb21tdW5pdGllcyBhbmQgcGxvdCBhIGhpc3RvZ3JhbSBvZiAkRF9FJCB2YWx1ZXMuCgpgYGB7ciBwbG90IEVkLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD01fQplX2RvbV9wbG90IDwtIHBsb3RfZV9kb20oZW5lcmdldGljX2RvbSkKZV9kb21fcGxvdApgYGAKCgojIyBTdGF0aXN0aWNhbCB0ZXN0cwoKIyMjIENvbXBhcmluZyBCU0VEcyB0byB1bmlmb3JtCgojIyMjIEVybmVzdCBhcHByb2FjaAoKLSBVc2UgYm9vdHN0cmFwIHNhbXBsaW5nIHRvIGNvbXBhcmUgdG8gdW5pZm9ybSBkaXN0cmlidXRpb25zLgotIEZvciBldmVyeSBjb21tdW5pdHksIGRyYXcgMTAwMDAgc2FtcGxlcyAoc2ltIGNvbW11bml0aWVzKToKLSBTYW1lIG51bWJlciBvZiBpbmRpdmlkdWFscyBhcyB0aGUgZW1waXJpY2FsIGNvbW11bml0eSwgZHJhd24gZnJvbSBhIHVuaWZvcm0gZGlzdHJpYnV0aW9uIHJhbmdpbmcgZnJvbSB0aGUgc21hbGxlc3QgdG8gbGFyZ2VzdCB+fmJvZHkgc2l6ZX5+IGluZGl2aWR1YWwgbWV0YWJvbGljIHJhdGUgb2YgYW55IGluZGl2aWR1YWwgaW4gdGhhdCBjb21tdW5pdHkuCi0gRm9yIHNpbSBjb21tdW5pdGllcyBhbmQgdGhlIGVtcGlyaWNhbCBjb21tdW5pdHksIGNhbGN1bGF0ZSBhIGRpc3RyaWJ1dGlvbiBvdmVybGFwIGluZGV4ICgkRE9JJCk6Ci0gJERPSSA9IFxzdW1fayB7fHlfe2FrfSAtIHlfe2JrfXx9JCB3aGVyZSAkeSQgaXMgdGhlIHZhbHVlIGZvciBzaXplIGNsYXNzICRrJCBpbiBjb21tdW5pdGllcyAkYSQgYW5kICRiJC4KLSAkRE9JJCB2YWx1ZXMgd2lsbCByYW5nZSBmcm9tIDAgKGNvbXBsZXRlIG92ZXJsYXApIHRvIDIgKG5vIG92ZXJsYXApLiAKLSBGb3IgdGhlIEJTRUQgYm9vdHN0cmFwcywgY29tbXVuaXR5ICRhJCBpcyB0aGUgZW1waXJpY2FsIG9yIHNpbSBkaXN0cmlidXRpb24sIGFuZCBjb21tdW5pdHkgJGIkIGlzIGEgdHJ1ZSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiB+fihpLmUuICR5X3tia30gPSBcZnJhY3sxfXtcbWF4KGspfSQgZm9yIGFsbCAkayQpfn4KLSAiVHJ1ZSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiI6IFRoZXJlIGFyZSBleGFjdGx5IHRoZSBzYW1lIG51bWJlciBvZiBpbmRpdmlkdWFscyBvZiBldmVyeSBzaXplLiAKLSBDYWxjdWxhdGUgdGhlICRET0kkIGZvciBhbGwgc2ltIGNvbW11bml0aWVzIGFuZCB0aGUgZW1waXJpY2FsLgotIEZpbmQgdGhlIHF1YW50aWxlIHZhbHVlIGZvciB0aGUgZW1waXJpY2FsICRET0kkIGNvbXBhcmVkIHRvIHRoZSBkaXN0cmlidXRpb24gb2Ygc2ltICRET0kkcy4gVGhpcyBpcyB0aGUgcC12YWx1ZTsgaS5lLiB0aGUgcHJvcG9ydGlvbiBvZiBzaW0gdW5pZm9ybSBkaXN0cmlidXRpb25zIHdpdGggRE9JcyBncmVhdGVyIHRoYW4gdGhlIGVtcGlyaWNhbC4KCiMjIyMgVHJhbnNsYXRpb24gdG8gYHJlcGxpY2F0ZS1iZWNzYAoKLSBGb3IgYSBnaXZlbiBlbXBpcmljYWwgY29tbXVuaXR5LCBkcmF3IDEwMDAwIHNpbSBjb21tdW5pdGllcyBlYWNoIHdpdGggdGhlIHNhbWUgbnVtYmVyIG9mIGluZGl2aWR1YWxzICRuJCwgd2l0aCBib2R5IHNpemVzIHJhbmRvbWx5IGRyYXduIGZyb20gYSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiBmcm9tIHRoZSBtaW5pbXVtIHRvIG1heGltdW0gYm9keSBzaXplIGluIHRoYXQgY29tbXVuaXR5LgotIENhbGN1bGF0ZSB0aGUgJERPSSQgb2YgZWFjaCBzaW0gY29tbXVuaXR5IGNvbXBhcmVkIHRvIGEgdHJ1ZSB1bmlmb3JtIGRpc3RyaWJ1dGlvbi4gCi0gVHJ1ZSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiA9IGV2ZXJ5IHNpemUgZnJvbSB0aGUgbWluaW11bSB0byB0aGUgbWF4aW11bSBzaXplIGluIHRoZSBjb21tdW5pdHkgKGJ5IC4xZykgaGFzIGV4YWN0bHkgb25lIGluZGl2aWR1YWwuCgpgYGB7ciBCU0VELXVuaWZvcm0gYm9vdHN0cmFwcGVkIERPSXMsIGV2YWwgPSBGfQoKYnNlZF91bmlmb3JtX2Jvb3RzdHJhcHMgPC0gbGFwcGx5KGNvbW11bml0aWVzLCBGVU4gPSBjb21tdW5pdHlfYm9vdHN0cmFwLCAgYm9vdHN0cmFwX2Z1bmN0aW9uID0gJ2Jvb3RzdHJhcF91bmlmX2JzZWRfZG9pJywgbmJvb3RzdHJhcHMgPSAxMDAwMCkKCmBgYAoKYGBge3Igc291cmNlIG9yIGRyYXcgQlNFRCB1bmlmb3JtIGJvb3RzdHJhcHMsIGluY2x1ZGUgPSBGfQppZihzb3VyY2Vfc2ltcykgewogIGxvYWQoZmlsZS5wYXRoKHN0b3JhZ2VwYXRoLCAnZGF0YScsICdzaW1zJywgJ2JzZWRfdW5pZm9ybV9ib290c3RyYXBzLlJkYXRhJykpCn0gZWxzZSB7CiAgCmJzZWRfdW5pZm9ybV9ib290c3RyYXBzIDwtIGxhcHBseShjb21tdW5pdGllcywgRlVOID0gY29tbXVuaXR5X2Jvb3RzdHJhcCwgIGJvb3RzdHJhcF9mdW5jdGlvbiA9ICdib290c3RyYXBfdW5pZl9ic2VkX2RvaScsIG5ib290c3RyYXBzID0gMTApCgpzYXZlKGJzZWRfdW5pZm9ybV9ib290c3RyYXBzLCBmaWxlID0gKGZpbGUucGF0aChzdG9yYWdlcGF0aCwgJ2RhdGEnLCAnc2ltcycsICdic2VkX3VuaWZvcm1fYm9vdHN0cmFwcy5SZGF0YScpKSkKfQpgYGAKCgpfU2VlIGlzc3VlICM0IG9uIGdpdGh1Yi5fCgoKYGBge3IgcGxvdCBCU0VELXVuaWZvcm0gYm9vdHN0cmFwIERPSXMgdiBlbXBpcmljYWwsZWNobz1GQUxTRSwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfSAKCmJzZWRfdW5pZm9ybV9ib290c3RyYXBfcGxvdCA8LSBwbG90X3BhcGVyX2Rpc3RzKGJzZWRfdW5pZm9ybV9ib290c3RyYXBzLCBkaXN0X3R5cGUgPSAnYnNlZF9ib290c3RyYXBzJykKCmludmlzaWJsZShic2VkX3VuaWZvcm1fYm9vdHN0cmFwX3Bsb3QpCmBgYAoKIyMjIENvbXBhcmUgQlNFRHMgYW1vbmcgY29tbXVuaXRpZXMKCiMjIyMgRXJuZXN0IGFwcHJvYWNoCi0gRm9yIGV2ZXJ5IHBhaXIgb2YgY29tbXVuaXRpZXMsIGNyZWF0ZSBhIHBvb2wgb2YgbWFzc2VzIG9mIGFsbCBpbmRpdmlkdWFscyBmcm9tIGJvdGggY29tbXVuaXRpZXMuCi0gRHJhdyB0d28gbmV3IGNvbW11bml0aWVzIHdpdGggdGhlIHNhbWUgbnVtYmVyIG9mIGluZGl2aWR1YWxzIGFzIHRoZSBlbXBpcmljYWwgY29tbXVuaXRpZXMsIHB1bGxpbmcgbWFzc2VzIGF0IHJhbmRvbSBmcm9tIHRoZSBwb29sLCB3aXRoIHJlcGxhY2VtZW50LgotIENhbGN1bGF0ZSB0aGUgRE9JIGZvciB0aGUgQlNFRHMgb2YgdGhlIHR3byBzYW1wbGUgY29tbXVuaXRpZXMuCi0gUmVwZWF0IDEwMDAwIGZvciBlYWNoIHBhaXIuCi0gVGhlIFAgdmFsdWUgaXMgdGhlIHByb3BvcnRpb24gb2Ygc2FtcGxlIERPSXMgZ3JlYXRlciAoaS5lLiBsZXNzIG92ZXJsYXApIHRoYW4gdGhlIGVtcGlyaWNhbCB2YWx1ZS4gCgojIyMjIFRyYW5zbGF0aW9uIHRvIGByZXBsaWNhdGUtYmVjc2AKLSBGb3IgZXZlcnkgcGFpciBvZiBjb21tdW5pdGllcywgcG9vbCBhbGwgdGhlIG1hc3NlcwotIFJlc2FtcGxlIHR3byBjb21tdW5pdGllcyBvZiB0aGUgcmlnaHQgc2l6ZXMKLSBDb25zdHJ1Y3QgQlNFRHMgZm9yIGJvdGggY29tbXVuaXRpZXMKLSBDYWxjdWxhdGUgdGhlIERPSSBvZiB0aGUgdHdvIEJTRURzCi0gUmVwZWF0IDEwMDAweAoKYGBge3IgcGFpcnMgZm9yIGNyb3NzY29tbXVuaXR5IEJTRUQgY29tcGFyaXNvbnN9CmNvbW11bml0eV9jb21iaW5hdGlvbl9pbmRpY2VzID0gdXRpbHM6OmNvbWJuKHggPSBjKDE6OSksIG0gPSAyLCBzaW1wbGlmeSA9IFRSVUUpICU+JQogIHQoKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgZHBseXI6OnJlbmFtZShjb21tdW5pdHlfYSA9IFYxLCBjb21tdW5pdHlfYiA9IFYyKQoKY29tYmluZV9jb21tdW5pdGllcyA9IGZ1bmN0aW9uKGluZGljZXMsIGNvbW11bml0aWVzKSB7CiAgY29tbXVuaXR5X2NvbWJpbmF0aW9uID0gbGlzdChjb21tdW5pdHlfYSA9IGNvbW11bml0aWVzW1tpbmRpY2VzWzFdXV0sIGNvbW11bml0eV9iID0gY29tbXVuaXRpZXNbW2luZGljZXNbMl1dXSwgY29tbXVuaXR5X25hbWVzID0gYyhuYW1lcyhjb21tdW5pdGllcylbW2luZGljZXNbMV1dXSwgbmFtZXMoY29tbXVuaXRpZXMpW1tpbmRpY2VzWzJdXV0pKQogIAogIHJldHVybihjb21tdW5pdHlfY29tYmluYXRpb24pCn0KCmNvbW11bml0eV9jb21iaW5hdGlvbnMgPSBhcHBseShjb21tdW5pdHlfY29tYmluYXRpb25faW5kaWNlcywgTUFSR0lOID0gMSwgRlVOID0gY29tYmluZV9jb21tdW5pdGllcywgY29tbXVuaXRpZXMgPSBjb21tdW5pdGllcykKCmBgYAoKYGBge3IgY3Jvc3MgY29tbXVuaXR5IEJTRUQgY29tcGFyaXNvbnMsIGV2YWwgPUZ9Cgpic2VkX2Nyb3NzY29tbV9ib290c3RyYXBzID0gbGFwcGx5KGNvbW11bml0eV9jb21iaW5hdGlvbnMsIEZVTiA9IGNvbW11bml0eV9ib290c3RyYXAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvb3RzdHJhcF9mdW5jdGlvbiA9ICdib290c3RyYXBfY3Jvc3Njb21tX2JzZWRzJywgbmJvb3RzdHJhcHMgPSAxMDAwMCkKCgpgYGAKCgpgYGB7ciBzb3VyY2Ugb3IgZHJhdyBjcm9zcyBjb21tdW5pdHkgQlNFRCwgaW5jbHVkZSA9IEZ9CmlmKHNvdXJjZV9zaW1zKSB7CiAgbG9hZChmaWxlLnBhdGgoc3RvcmFnZXBhdGgsICdkYXRhJywgJ3NpbXMnLCAnYnNlZF9jcm9zc2NvbW1fYm9vdHN0cmFwcy5SZGF0YScpKQp9IGVsc2UgewogIApic2VkX2Nyb3NzY29tbV9ib290c3RyYXBzID0gbGFwcGx5KGNvbW11bml0eV9jb21iaW5hdGlvbnMsIEZVTiA9IGNvbW11bml0eV9ib290c3RyYXAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvb3RzdHJhcF9mdW5jdGlvbiA9ICdib290c3RyYXBfY3Jvc3Njb21tX2JzZWRzJywgbmJvb3RzdHJhcHMgPSAxMCkKCnNhdmUoYnNlZF9jcm9zc2NvbW1fYm9vdHN0cmFwcywgZmlsZSA9IChmaWxlLnBhdGgoc3RvcmFnZXBhdGgsICdkYXRhJywgJ3NpbXMnLCAnYnNlZF9jcm9zc2NvbW1fYm9vdHN0cmFwcy5SZGF0YScpKSkKfQpgYGAKCmBgYHtyIHBsb3QgY3Jvc3MgY29tbXVuaXR5IGNvbXBhcmlzb25zLCBlY2hvID0gRiwgZmlnLmhlaWdodD0zMCwgZmlnLndpZHRoPTEwfQoKY3Jvc3Njb21tX2Jvb3RzdHJhcF9wbG90ID0gcGxvdF9jcm9zc2NvbW1fYnNlZHMoYnNlZF9jcm9zc2NvbW1fYm9vdHN0cmFwcykKCmludmlzaWJsZShjcm9zc2NvbW1fYm9vdHN0cmFwX3Bsb3QpCgpgYGAKCmBgYHtyIHBsb3QgY3Jvc3MgY29tbXVuaXR5IHAgdmFsdWVzLCBlY2hvID0gRiwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDV9CnB2YWxzX2hpc3RvZ3JhbSA9IHBsb3RfYm9vdHN0cmFwX3B2YWxzKGJzZWRfY3Jvc3Njb21tX2Jvb3RzdHJhcHMpCgpwdmFsc19oaXN0b2dyYW0KYGBgCgoKU2VlIGhpc3RvZ3JhbSBvZiBwIHZhbHVlcyBmb3IgY29tcGFyaXNvbnMgdG8gc2VlIGlmIGNvbW11aXRpZXMnIEJTRURzIGFyZSB0aGUgc2FtZSBvciBkaWZmZXJlbnQuCgojIyMgVGVzdGluZyBCU0RzIGZvciB1bmlmb3JtaXR5CgojIyMjIEVybmVzdCBhcHByb2FjaAotICRcZGVsdGEkLWNvcnJlY3RlZCBLb2xtb2dvcm92LVNtaXJub3YgdGVzdC4gCi0gIlRoZSAkXGRlbHRhJC1jb3JyZWN0ZWQgSy1TIHRlc3QgaW5jcmVhc2VzIHRoZSBwb3dlciBvZiB0aGUgdGVzdCB3aGVuIHNhbXBsZSBzaXplcyBhcmUgc21hbGwgKG4gPCAyNTsgWmFyIDE5OTkpIgotIFRoZSAkXGRlbHRhJC1jb3JyZWN0ZWQgdGVzdCBpcyBub3Qgd2lkZWx5IGRpc2N1c3NlZCBvbmxpbmUuIAoKCmBgYHtyIGVybmVzdCBkIGtzIHRlc3QgcmVzdWx0c30KZXJuZXN0X2tleSA9ICByZWFkLmNzdihmaWxlLnBhdGgoc3RvcmFnZXBhdGgsICdlcm5lc3QtMjAwNS1maWxlcycsICdlcm5lc3Rfa2V5LmNzdicpLCBzdHJpbmdzQXNGYWN0b3JzID0gRikKZXJuZXN0X2JzZHNfdW5pZm9ybV9yZXN1bHRzID0gcmVhZC5jc3YoZmlsZS5wYXRoKHN0b3JhZ2VwYXRoLCAnZXJuZXN0LTIwMDUtZmlsZXMnLCAnZXJuZXN0X2FwcGVuZGl4QS5jc3YnKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpICU+JQogIGRwbHlyOjpsZWZ0X2pvaW4oZXJuZXN0X2tleSwgYnkgPSAnc2l0ZScpCnByaW50KGVybmVzdF9ic2RzX3VuaWZvcm1fcmVzdWx0cykKYGBgCgoKIyMjIyBUcmFuc2xhdGlvbiB0byBgcmVwbGljYXRlLWJlY3NgOgoKCipGcm9tIFphciAoMTk5OSkgX0Jpb3N0YXRpc3RpY2FsIEFuYWx5c2lzXy4qCgojIyMjIyBCYXNlIEstUyB0ZXN0Ci0gVGFrZSB2ZWN0b3Igb2YgbWVhc3VyZW1lbnRzICRYX2kkLiAKLSBGb3IgZWFjaCAkWF9pJCByZWNvcmQgdGhlIG9ic2VydmVkIGZyZXF1ZW5jeSAkZl9pJCAobnVtYmVyIG9mIG9ic2VydmF0aW9ucyB3aXRoIHRoYXQgdmFsdWUpLgotIERldGVybWluZSBjdW11bGF0aXZlIG9ic2VydmVkIGZyZXF1ZW5jaWVzICRGX2kkIGFuZCBjdW11bGF0aXZlIHJlbGF0aXZlIGZyZXF1ZW5jaWVzICRcdGV4dHJte3JlbH1GX2kkOgotICRcdGV4dHJte3JlbH1GX2kgPSBcZnJhY3tGX2l9e259JCB3aGVyZSAkbiQgaXMgdGhlIG51bWJlciBvZiBtZWFzdXJlbWVudHMgdGFrZW4uIAotICRcdGV4dHJte3JlbH1GX2kkIGlzIHRoZSBwcm9wb3J0aW9uIG9mIHRoZSBzYW1wbGUgdGhhdCBpcyBtZWFzdXJlbWVudHMgJFxsZXEgWF9pJC4gCi0gRm9yIGVhY2ggJFhfaSQsIGRldGVybWluZSB0aGUgY3VtdWxhdGl2ZSAqcmVsYXRpdmUqIGV4cGVjdGVkIGZyZXF1ZW5jeSBmcm9tIHRoZSBjb21wYXJpc29uIGRpc3RyaWJ1dGlvbiwgJFx0ZXh0cm17cmVsfVxoYXR7Rl9pfSQuCi0gRm9yIGEgdW5pZm9ybSBkaXN0cmlidXRpb24sICRcdGV4dHJte3JlbH1caGF0e0ZfaX0gPSBcZnJhY3tYX2kgLSBcbWluKFgpfXtcbWF4KFgpIC0gXG1pbihYKX0kCi0gRGV0ZXJtaW5lICREX2kkIGFuZCAkRCdfaSQgYXM6Ci0gJERfaSA9IHx7XHRleHRybXtyZWx9Rl9pIC0gXHRleHRybXtyZWx9XGhhdHtGX2l9fXwkCi0gJEQnX2kgPSB8e1x0ZXh0cm17cmVsfUZfe2ktMX0gLSBcdGV4dHJte3JlbH1caGF0e0ZfaX19fCQKLSBub3RlICRGXzAgPSAwJCBzbyAkRCdfMSA9IFx0ZXh0cm17cmVsfVxoYXR7Rl9pfSQKLSBUaGUgdGVzdCBzdGF0aXN0aWMgJEQkIGlzOgotICREID0gXG1heFsoXG1heChEX2kpLCAoXG1heChEJ19pKV0kCi0gQ29tcGFyZSB0byBjcml0aWNhbCB2YWx1ZXMgZnJvbSBhcHBlbmRpeC4KCgojIyMjIyAkXGRlbHRhJC1jb3JyZWN0ZWQgS1MgdGVzdAoKLSBGb3Igc21hbGwgc2FtcGxlIHNpemVzICg8MjUpIHdlIGNhbiBvYnRhaW4gaW5jcmVhc2VkIHBvd2VyIHVzaW5nIHRoZSAkXGRlbHRhJC1jb3JyZWN0ZWQgS1MgdGVzdC4KLSBGb3IgZWFjaCAkaSQgZGV0ZXJtaW5lCi0gJFx0ZXh0cm17cmVsfUdfaSA9IFxmcmFje0ZfaX17biArIDF9JAotICRcdGV4dHJte3JlbH1HJ19pID0gXGZyYWN7Rl9pIC0gMX17biAtIDF9JAotIFRoZW4gb2J0YWluIHNpbWlsYXIgJEQkcwotICREX3swLCBpfSA9IHxcdGV4dHJte3JlbH1HX2kgLSBcdGV4dHJte3JlbH1caGF0e0ZfaX18JAotICREX3sxLCBpfSA9IHxcdGV4dHJte3JlbH1HJ19pIC0gXHRleHRybXtyZWx9XGhhdHtGX2l9fCQKLSBUaGUgdGVzdCBzdGF0aXN0aWMgaXMgZWl0aGVyICRcbWF4KERfezAsIGl9KSQgb3IgJFxtYXgoRF97MSwgaX0pJCwgd2hpY2hldmVyIGxlYWRzIHRvIHRoZSBoaWdoZXN0IGxldmVsIG9mIHNpZ25pZmljYW5jZS9zbWFsbGVzdCBwcm9iYWJpbGl0eS4gTG9vayB1cCBzaWduaWZpY2FuY2UgaW4gdGFibGUgZnJvbSBhcHBlbmRpeC4gVGhlIDEgYW5kIDAgYXJlIHRoZSAkXGRlbHRhJHMuIAoKClRhYmxlcyBvZiBjcml0aWNhbCB2YWx1ZXMgd2VyZSBlbnRlcmVkIGJ5IGhhbmQgZnJvbSB0aGUgYXBwZW5kaXggdG8gWmFyICgxOTk5KS4KCmBgYHtyIGJzZHMgZGVsdGFrcyB0byB1bmlmb3JtLCBlY2hvID0gRn0KYnNkX2tzX3Rlc3RfcmF3ID0gbGFwcGx5KGJzZHMsIEZVTiA9IHphcl9rc190ZXN0LCBkZWx0YV9jb3JyZWN0aW9uID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgIGZvY2FsX2NvbHVtbiA9ICdzcGVjaWVzX21lYW5fbWFzcycsCiAgICAgICAgICAgICAgICAgICAgICAgICBleHBlY3RlZF9yYW5nZSA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICBuX29yX2kgPSAnbicsCiAgICAgICAgICAgICAgICAgICAgICAgICBzdG9yYWdlcGF0aCA9IHN0b3JhZ2VwYXRoKQoKYnNkX2tzX3Rlc3RfcmF3X3Jlc3VsdHMgPSBkYXRhLmZyYW1lKAogIGNvbW11bml0eV9uYW1lID0gYXMuY2hhcmFjdGVyKG5hbWVzKGJzZF9rc190ZXN0X3JhdykpLAogIHNpZ25pZiA9IHZhcHBseShic2Rfa3NfdGVzdF9yYXcsIEZVTiA9IGV4dHJhY3RfdmFsdWVzX3phcmtzLCB2YWxfbmFtZSA9ICJzaWduaWYiLCBGVU4uVkFMVUUgPSBUUlVFKSwKICBwX21heCA9IHZhcHBseShic2Rfa3NfdGVzdF9yYXcsIEZVTiA9IGV4dHJhY3RfdmFsdWVzX3phcmtzLCB2YWxfbmFtZSA9ICJwX21heCIsIEZVTi5WQUxVRSA9IC4xKSwgCiAgcF9taW4gPSB2YXBwbHkoYnNkX2tzX3Rlc3RfcmF3LCBGVU4gPSBleHRyYWN0X3ZhbHVlc196YXJrcywgdmFsX25hbWUgPSAicF9taW4iLCBGVU4uVkFMVUUgPSAuMSksCiAgZF9zdGF0aXN0aWMgPSB2YXBwbHkoYnNkX2tzX3Rlc3RfcmF3LCBGVU4gPSBleHRyYWN0X3ZhbHVlc196YXJrcywgdmFsX25hbWUgPSAiZCIsIEZVTi5WQUxVRSA9IC4xKSwKICBzdHJpbmdzQXNGYWN0b3JzID0gRgopICU+JSAKICBkcGx5cjo6bGVmdF9qb2luKGVybmVzdF9ic2RzX3VuaWZvcm1fcmVzdWx0cywgYnkgPSAnY29tbXVuaXR5X25hbWUnKQoKcHJpbnQoYnNkX2tzX3Rlc3RfcmF3X3Jlc3VsdHMpCgpgYGAKClRoZSAkXGRlbHRhJCBjb3JyZWN0ZWQgS1MgdGVzdCBkb2VzIG5vdCBjb3JyZXNwb25kIHRvIHRoZSByZXN1bHRzIGZyb20gRXJuZXN0IHdoZW4gdGhlIHNwZWNpZXMgbWVhbiBib2R5IHNpemUgdmFsdWVzIGFyZSBvbiBhbiB1bnRyYW5zZm9ybWVkIHNjYWxlLiAKClVzaW5nIHRoZSBuYXR1cmFsIGxvZyBvZiB0aGUgc3BlY2llcyBtZWFuIGJvZHkgc2l6ZSB2YWx1ZSwgaG93ZXZlci4uLjoKCmBgYHtyIGJzZHMgZGVsdGFrcyB0byB1bmlmb3JtIGxvZywgZWNobyA9Rn0KYnNkX2tzX3Rlc3RfbG9nID0gbGFwcGx5KGJzZHMsIEZVTiA9IHphcl9rc190ZXN0LCBkZWx0YV9jb3JyZWN0aW9uID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgIGZvY2FsX2NvbHVtbiA9ICdsbl9tYXNzJywKICAgICAgICAgICAgICAgICAgICAgICAgIGV4cGVjdGVkX3JhbmdlID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgIG5fb3JfaSA9ICduJywKICAgICAgICAgICAgICAgICAgICAgICAgIHN0b3JhZ2VwYXRoID0gc3RvcmFnZXBhdGgpCgpic2Rfa3NfdGVzdF9sb2dfcmVzdWx0cyA9IGRhdGEuZnJhbWUoCiAgY29tbXVuaXR5X25hbWUgPSBhcy5jaGFyYWN0ZXIobmFtZXMoYnNkX2tzX3Rlc3RfbG9nKSksCiAgc2lnbmlmID0gdmFwcGx5KGJzZF9rc190ZXN0X2xvZywgRlVOID0gZXh0cmFjdF92YWx1ZXNfemFya3MsIHZhbF9uYW1lID0gInNpZ25pZiIsIEZVTi5WQUxVRSA9IFRSVUUpLAogIHBfbWF4ID0gdmFwcGx5KGJzZF9rc190ZXN0X2xvZywgRlVOID0gZXh0cmFjdF92YWx1ZXNfemFya3MsIHZhbF9uYW1lID0gInBfbWF4IiwgRlVOLlZBTFVFID0gLjEpLCAKICBwX21pbiA9IHZhcHBseShic2Rfa3NfdGVzdF9sb2csIEZVTiA9IGV4dHJhY3RfdmFsdWVzX3phcmtzLCB2YWxfbmFtZSA9ICJwX21pbiIsIEZVTi5WQUxVRSA9IC4xKSwKICBkX3N0YXRpc3RpYyA9IHZhcHBseShic2Rfa3NfdGVzdF9sb2csIEZVTiA9IGV4dHJhY3RfdmFsdWVzX3phcmtzLCB2YWxfbmFtZSA9ICJkIiwgRlVOLlZBTFVFID0gLjEpLAogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGCikgJT4lIAogIGRwbHlyOjpsZWZ0X2pvaW4oZXJuZXN0X2JzZHNfdW5pZm9ybV9yZXN1bHRzLCBieSA9ICdjb21tdW5pdHlfbmFtZScpCgpwcmludChic2Rfa3NfdGVzdF9sb2dfcmVzdWx0cykKYGBgCgpXaXRoIG1lYW4gbWFzcyBsb2dnZWQsIGFsbCB0aGUgcmVzdWx0cyByZXBsaWNhdGUgcXVhbGl0YXRpdmVseSAoaS5lLiBub3Qgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSB1bmlmb3JtKSBhbmQgTml3b3QsIGZvciB3aGljaCB0aGUgY3VycmVudGx5LWF2YWlsYWJsZSBkYXRhIG1vc3QgY2xvc2VseSBtYXRjaGVzIHRoYXQgcmVwb3J0ZWQgaW4gRXJuZXN0ICgyMDA1KSwgcmVwbGljYXRlcyBhbG1vc3QgZXhhY3RseSBudW1lcmljYWxseS4gCgojIyMgQ29tcGFyaW5nIEJTRHMgYW1vbmcgY29tbXVuaXRpZXMKCiMjIyMgRXJuZXN0IGFwcHJvYWNoCgpFcm5lc3QgKDIwMDUpIHVzZWQgYSB0d28tc2FtcGxlIEtvbG1vZ29yb3YtU21pcm5vdiB0ZXN0IHRvIGNvbXBhcmUgZXZlcnkgcG9zc2libGUgY29tYmluYXRpb24gb2YgY29tbXVuaXR5LWxldmVsIEJTRHMuIAoKYGBge3IgZXJuZXN0IGtzIHR3byBzYW1wbGUgcmVzdWx0cywgZWNobyA9Rn0KYXBwZW5kaXhfYiA9IHRpZHlfYXBwZW5kaXhfYihzdG9yYWdlcGF0aCA9IHN0b3JhZ2VwYXRoKSAlPiUKICBkcGx5cjo6bGVmdF9qb2luKGVybmVzdF9rZXksIGJ5ID0gYygnc2l0ZV9hJyA9ICdzaXRlJykpICU+JQogIGRwbHlyOjpyZW5hbWUoY29tbXVuaXR5X2EgPSBjb21tdW5pdHlfbmFtZSkgJT4lCiAgZHBseXI6OmxlZnRfam9pbihlcm5lc3Rfa2V5LCBieSA9IGMoJ3NpdGVfYicgPSAnc2l0ZScpKSAlPiUKICBkcGx5cjo6cmVuYW1lKGNvbW11bml0eV9iID0gY29tbXVuaXR5X25hbWUpCgpwcmludChhcHBlbmRpeF9iKQoKYGBgCgoKCiMjIyMgVHJhbnNsYXRpb24gdG8gYHJlcGxpY2F0ZS1iZWNzYAoKYGBge3Iga3MgdHdvIHNhbXBsZX0KCiMgdXNlIHNhbWUgY29tbXVuaXR5IGNvbWJpbmF0aW9ucyBhcyBiZWZvcmUKCmJzZF9jcm9zc2NvbW1fa3MgPSBsYXBwbHkoY29tbXVuaXR5X2NvbWJpbmF0aW9ucywgRlVOID0ga3NfYnNkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBsbl9tYXNzX3ZhbHMgPSBGKQoKYGBgCgpgYGB7ciBwcmludCBrcyB0d28gc2FtcGxlLCBlY2hvID0gRn0KYnNkX2Nyb3NzY29tbV9yZXN1bHRzID0gZGF0YS5mcmFtZSgKICBjb21tdW5pdHlfYSA9IHZhcHBseShic2RfY3Jvc3Njb21tX2tzLCBGVU4gPSBleHRyYWN0X3ZhbHVlc190c2tzLCB2YWxfbmFtZSA9ICJjb21tdW5pdHlfYSIsIEZVTi5WQUxVRSA9ICdwb3J0YWwnKSwKICBjb21tdW5pdHlfYiA9IHZhcHBseShic2RfY3Jvc3Njb21tX2tzLCBGVU4gPSBleHRyYWN0X3ZhbHVlc190c2tzLCB2YWxfbmFtZSA9ICJjb21tdW5pdHlfYiIsIEZVTi5WQUxVRSA9ICdwb3J0YWwnKSwKICBrc19kID0gIHZhcHBseShic2RfY3Jvc3Njb21tX2tzLCBGVU4gPSBleHRyYWN0X3ZhbHVlc190c2tzLCB2YWxfbmFtZSA9ICJzdGF0aXN0aWMiLCBGVU4uVkFMVUUgPSAuNSksCiAgICBwX3ZhbHVlID0gIHZhcHBseShic2RfY3Jvc3Njb21tX2tzLCBGVU4gPSBleHRyYWN0X3ZhbHVlc190c2tzLCB2YWxfbmFtZSA9ICJwLnZhbHVlIiwgRlVOLlZBTFVFID0gLjUpLAogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGCikKCgpic2RfY3Jvc3Njb21tX2pvaW5lZCA9IGJzZF9jcm9zc2NvbW1fcmVzdWx0cyAlPiUKICBkcGx5cjo6bGVmdF9qb2luKGFwcGVuZGl4X2IsIGJ5ID0gYygnY29tbXVuaXR5X2EnLCAnY29tbXVuaXR5X2InKSkgJT4lCiAgbmEub21pdCgpCgpic2RfY3Jvc3Njb21tX2pvaW5lZDIgPSBic2RfY3Jvc3Njb21tX3Jlc3VsdHMgJT4lCiAgZHBseXI6OnJlbmFtZShjb21tdW5pdHlfYiA9IGNvbW11bml0eV9hLCBjb21tdW5pdHlfYSA9IGNvbW11bml0eV9iKSAlPiUKICBkcGx5cjo6bGVmdF9qb2luKGFwcGVuZGl4X2IsIGJ5ID0gYygnY29tbXVuaXR5X2EnLCAnY29tbXVuaXR5X2InKSkgJT4lCiAgbmEub21pdCgpICU+JQogIGRwbHlyOjpiaW5kX3Jvd3MoYnNkX2Nyb3NzY29tbV9qb2luZWQpCgpwcmludChic2RfY3Jvc3Njb21tX2pvaW5lZDIpCgpgYGAKCmBgYHtyIHBsb3QgYnNkIGNyb3NzY29tbSBwdmFsIGhpc3QsIGVjaG8gPUYsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfSAKYnNkX3B2YWxzX2hpc3RvZ3JhbSA9IHBsb3RfY3Jvc3Njb21tX2tzX3B2YWxzKGJzZF9jcm9zc2NvbW1fam9pbmVkMikKCmludmlzaWJsZShic2RfcHZhbHNfaGlzdG9ncmFtKQpgYGAKCg==